package com.theta.gateway.infra.routecfg.model.converter;

import java.net.URI;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;

import com.google.common.collect.Lists;
import com.theta.gateway.infra.common.constants.SystemConstant;
import com.theta.gateway.infra.common.enums.SsoValidateTypeEnum;
import com.theta.gateway.infra.common.utils.BeanCopierUtils;
import com.theta.gateway.infra.common.utils.JsonUtil;
import com.theta.gateway.infra.common.utils.StrUtil;
import com.theta.gateway.infra.routecfg.model.dataobject.response.CommonObjectDO;
import com.theta.gateway.infra.routecfg.model.dataobject.response.RouteCfgDO;
import com.theta.gateway.infra.routecfg.model.dataobject.response.RouteInfoDO;
import com.theta.gateway.infra.routecfg.model.dataobject.response.RouteInfoFilterDO;
import com.theta.gateway.infra.routecfg.model.dataobject.response.RouteInfoPredicateDO;
import com.theta.gateway.infra.routecfg.model.entity.RouteCfgEntity;

import lombok.extern.slf4j.Slf4j;

/**
 * 路由信息转换类
 * @author theta
 *
 */
@Slf4j
public class RouteDTOConverter {
	
	
	/**
	 * 将路由dto信息转换成gateway路由对象
	 * @param routeInfo
	 * @return
	 */
	public static RouteDefinition convertDto2RouteDefinition(RouteInfoDO routeInfo) {
		RouteDefinition route=null;
		if(routeInfo!=null && StringUtils.isNotBlank(routeInfo.getUri())) {
			route=new RouteDefinition();
			route.setId(routeInfo.getRouteId());
			route.setOrder(StrUtil.obj2Integer(routeInfo.getOrder(), 1));
			//设置路由断言信息
			if(routeInfo.getPredicates()!=null) {
				List<PredicateDefinition> predicates=Lists.newArrayList();
				routeInfo.getPredicates().stream().forEach(p->{
					predicates.add(newPredicateDefinition(p.getName(), p.getArgs()));
				});
				route.setPredicates(predicates);
			}
			
			//设置路由过滤器
			if(routeInfo.getFilters()!=null) {
				List<FilterDefinition> filters=Lists.newArrayList();
				routeInfo.getFilters().stream().forEach(p->{
					filters.add(newFilterDefinition(p.getName(), p.getArgs()));
				});
				route.setFilters(filters);
			}
			//
			route.setUri(URI.create(routeInfo.getUri()));
		}
		return route;
	}
	
	/**
	 * 创建网关断言定义对象
	 * @param name
	 * @param args
	 * @return
	 */
	private static PredicateDefinition newPredicateDefinition(String name,Map<String, String> args) {
		PredicateDefinition pd=new PredicateDefinition();
		pd.setName(name);
		pd.setArgs(args);
		return pd;
	}
	
	/**
	 * 创建网关filter定义对象
	 * @param name
	 * @param args
	 * @return
	 */
	private static FilterDefinition newFilterDefinition(String name,Map<String, String> args) {
		FilterDefinition pd=new FilterDefinition();
		pd.setName(name);
		pd.setArgs(args);
		return pd;
	}
	
	
	public static RouteInfoDO convertRouteDefinition2DTO(RouteDefinition def) {
		RouteInfoDO dto=new RouteInfoDO();
		dto.setRouteId(def.getId());
		dto.setUri(def.getUri().toString());
		dto.setOrder(def.getOrder());
		def.getPredicates().stream().forEach(p->{
			dto.addPredicate(RouteInfoPredicateDO.builder().name(p.getName())
			.args(p.getArgs()).build());
		});
		def.getFilters().stream().forEach(f->{
			dto.addFilter(RouteInfoFilterDO.builder().name(f.getName())
					.args(f.getArgs()).build());
		});
		return dto;
	}
	
	public static List<RouteInfoDO> convertRouteDefinition2DTOBatch(List<RouteDefinition> routeDefs) {
		List<RouteInfoDO> routes=Lists.newArrayList();
		routeDefs.stream().forEach(def->{
			routes.add(convertRouteDefinition2DTO(def));
		});
		
		return routes;
	}
	
	
	

	/**
	 * 将路由规则dto信息转换成 网关所需的路由格式
	 * @param cfgDo
	 * @return
	 */
	public static RouteInfoDO convertCfg2InfoDo(RouteCfgDO cfgDo){
		RouteInfoDO dto=new RouteInfoDO();
//		dto.setRouteId(StringUtils.join(cfgDto.getServiceId(),cfgDto.getId()));
		dto.setRouteId(SystemConstant.genRouteId(cfgDo.getId()));
		cfgDo.setUri(SystemConstant.genRouteUri(cfgDo.getUri()));
		dto.setUri(StrUtil.isNotEmpty(cfgDo.getUri())?cfgDo.getUri():SystemConstant.getGatewayRouteUri(cfgDo.getServiceId()));
		
		dto.setOrder(cfgDo.getOrderNo());
		dto.addPredicate(RouteInfoPredicateDO.builder()
				.name(SystemConstant.getRoutePredicatePathName()).build()
				.addArgs(SystemConstant.getRoutePredicateArgName(0), cfgDo.getPath()));
		dto.setFilters(convertFilterJson2Dolist(cfgDo.getRouteFilterJson()));
		
		//接入sso处理 为设置为接入sso的应用绑定登陆认证校验的filter
		if(StrUtil.obj2Integer(cfgDo.getIsJoinSso()).intValue()>SsoValidateTypeEnum.NOT_VALIDATE.getCode().intValue()) {
			//获取token校验filter name
			SsoValidateTypeEnum typeEnum=SsoValidateTypeEnum.getByCode(cfgDo.getIsJoinSso());
			dto.addFilter(RouteInfoFilterDO.builder()
					//.name(SystemConstant.SSO_AUTHEN_FILTER_NAME)
					.name(typeEnum.getFilterName())
				.build().addArgs("name", StringUtils.join(cfgDo.getServiceId(),"#",cfgDo.getId())));
		}
		return dto;
	}
	
	/**
	 * 将json格式的filter转换成 filterDo
	 * @param filterJson
	 * @return
	 */
	public static List<RouteInfoFilterDO> convertFilterJson2Dolist(String filterJson){
		List<RouteInfoFilterDO> filters =Lists.newArrayList();
		if(StrUtil.isEmpty(filterJson)) {
			return filters;
		}
		List<CommonObjectDO> filterObjs = JsonUtil.toList(filterJson, CommonObjectDO.class);
		int index=0;
		for(CommonObjectDO f:filterObjs) {
			if(StrUtil.isEmpty(f.getName()) || StrUtil.isEmpty(f.getValue()))continue;
			String[] filterValues= f.getValue().split(";");
			RouteInfoFilterDO filterDo=RouteInfoFilterDO.builder().name(f.getName()).build();
			for(String cfgVal:filterValues) {
				String[] values=cfgVal.split(":");
				if(values.length>1) {
					filterDo.addArgs(values[0].trim(),values[1].trim() );
				}else {
					filterDo.addArgs(SystemConstant.getRoutePredicateArgName(index), values[0].trim());
					index++;
				}
			}
			filters.add(filterDo);
		}
		return filters;
	}
	
	/**
	 * 将路由配置entity 转换为do实例
	 * @param cfgDo
	 * @return
	 */
	public static RouteCfgDO convertRouteEntity2DTO(RouteCfgEntity cfgDo) {
		RouteCfgDO cfgDto=null;
		if(cfgDo!=null) {
			cfgDto=new RouteCfgDO();
			BeanCopierUtils.copyProperties(cfgDo, cfgDto);
		}
		return cfgDto;
	}
	
}
